class DoublyLinkedList {

    constructor() {
        this.head = null;
        this.tail = null;
        this.numberNode = 0;
    }

    add(val) {
        let node = new LinkedNode(val);
        if (!this.head) {
            this.head = node;
            this.tail = node;
        } else {
            this.tail.next = node;
            node.prev = this.tail;
            this.tail = node;
        }
        this.numberNode ++;
    }

    insertAfter(val, targetVal) {
        let targetNode = this.find(targetVal);
        if (!targetNode) return;

        if (targetNode === this.tail) {
            this.add(val)
        } else {
            let node = new LinkedNode(val);

            node.next = targetNode.next;
            targetNode.next.prev = node;

            node.prev = targetNode;
            targetNode.next = node;
            this.numberNode++;
        }
    }

    remove(val) {
        let node = this.head;

        while (node) {
            if (node.val === val) {
                if (node === this.head && node === this.tail) {
                    this.head = null;
                    this.tail = null;
                } else if (node === this.head) {
                    this.head = node.next;
                    this.head.prev = null;
                } else if (node === this.tail) {
                    this.tail = node.prev;
                    this.tail.next = null;
                } else {
                    node.next.prev = node.prev;
                    node.prev.next = node.next;
                }

                this.numberNode --;
            }

            node = node.next;
        }
    }

    find(val) {
        let node = this.head;
        while (node) {
            if (node.val === val) {
                return node;
            } else {
                node = node.next;
            }
        }
    }

    traverse(fn) {
        let node = this.head;
        while (node) {
            fn(node);
            node = node.next;
        }
    }

    traverseReverse(fn) {
        let node = this.tail;
        while (node) {
            fn(node);
            node = node.prev;
        }
    }

    length() {
        return this.numberNode;
    }

    toString() {
        let str = "";
        this.traverse((node) => {str += node.val + " "});
        return str;
    }

    print() {
        console.log(this.toString());
    }
}

class LinkedNode {
    constructor(val) {
        this.val = val;
        this.next = null;
        this.prev = null;
    }
}

exports.DoublyLinkedList = DoublyLinkedList;